/*
    创建TCP套接字类
    要进行网络通信：需要创建sock套接字
*/
#pragma once
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <string>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include <unistd.h>

#include "Err.hpp"
#include "Log.hpp"

const int defaultscok = -1;
static const int defaultbacklog = 32;
class Sock
{
public:
    Sock(int sock = defaultscok) : _sock(sock)
    {
    }
    // 创建套接字->socket
    void Socket()
    {
        /* int socket(int domain, int type, int protocol);*/
        _sock = socket(AF_INET, SOCK_STREAM, 0);
        if (_sock < 0)
        {
            logMessage(Fatal, "code:%d socket create error:%s", errno, strerror(errno));
            exit(SOCKET_ERROR);
        }
    }

    // 绑定服务器的IP和端口port->bind 注意：云服务器不需要自己绑定IP
    void Bind(uint16_t port)
    {
        /*int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);*/
        struct sockaddr_in peer;
        memset(&peer, 0, sizeof(peer));
        peer.sin_family = AF_INET;
        peer.sin_port = htons(port);
        peer.sin_addr.s_addr = INADDR_ANY;
        if (bind(_sock, (struct sockaddr *)&peer, sizeof(peer)) < 0)
        {
            logMessage(Fatal, "code:%d bind sock error:%s", errno, strerror(errno));
            exit(BIND_ERROR);
        }
    }

    // 服务器与客户端建立连接->listen
    void Listen()
    {
        /*int listen(int sockfd, int backlog);*/
        if (listen(_sock, defaultbacklog) < 0)
        {
            logMessage(Fatal, "code:%d listen sock error:%s", errno, strerror(errno));
            exit(LISTEN_ERROR);
        }
    }

    // 服务器创建新的套接字sock,并且获取客户端的IP和port-> accept
    int Accept(std::string *clientip, uint16_t *port)
    {
        /* int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);*/

        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        int sock = accept(_sock, (struct sockaddr *)&client, &len);
        if (sock < 0)
        {
            logMessage(Warning, "code:%d listen sock error:%s", errno, strerror(errno));
        }
        else if (sock > 0)
        {
            *clientip = inet_ntoa(client.sin_addr);
            *port = ntohs(client.sin_port);
        }
        return sock;
    }

    // 客户端请求连接服务器->connect
    int Connect(std::string serverip, uint16_t serverport)
    {
        /*int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);*/
        struct sockaddr_in server;
        server.sin_family = AF_INET;
        server.sin_addr.s_addr = inet_addr(serverip.c_str());
        server.sin_port = htons(serverport);
        return connect(_sock, (struct sockaddr *)&server, sizeof(server));
    }
    int Fd()
    {
        return _sock;
    }
    void Close()
    {
        if (_sock != defaultscok)
            close(_sock);
    }
    ~Sock()
    {
    }

private:
    int _sock;
};